#pragma once
#include <iostream>
#include <cassert>
#include <mutex>
#include <list>


#ifdef _WIN32
#include <windows.h>

#else
#include <sys/mman.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>

#endif

// 小于等于MAX_BYTES，就找thread cache申请
// 大于MAX_BYTES，就直接找page cache或者系统堆申请
static const size_t NFREELIST = 112;	            // central cache自由链表哈希桶的表大小
static const size_t NPAGES = 256 + 1;	            // page cache 管理span list哈希表大小
static const size_t PAGE_SHIFT = 12;	            // 系统页大小
static const size_t MY_PAGE_SHIFT = 18;	            // 页大小转换偏移, 即一页定义为2^18,也就是256KB
static const size_t MAX_BYTES = 1 << MY_PAGE_SHIFT;
static const size_t MAX_SHM_COUNT = 1024;           // 最大共享内存文件数量

#if defined(_WIN64) || defined(__x86_64__)
// 64位Windows或Linux系统
typedef unsigned long long PAGE_ID;
static const size_t WINNUM = 64;

#elif defined(_WIN32) || defined(__i386__)
// 32位Windows或Linux系统
typedef size_t PAGE_ID;
static const size_t WINNUM = 32;

#else
// 其他情况，根据实际情况定义PAGE_ID的类型和WINNUM的值

#endif


// 获取对象头部的地址指针
static void*& NextObj(void* obj) {
    // 32位下*(void**)是4个字节
    // 64位下*(void**)是8个字节
    return *(reinterpret_cast<void**>(obj));
}

// 获取起始位置8个字节后的四个字节存储的int32_t引用
static int32_t& ObjPos(void* obj) {
    // 将obj转换为char*类型，以便进行字节级别的指针运算
    // 然后加上8，获取偏移8个字节后的地址
    // 最后将其转换为int32_t*类型，并解引用以返回int32_t引用
    return *(reinterpret_cast<int32_t*>(reinterpret_cast<char*>(obj) + 8));
}

// 获取起始位置12个字节后的四个字节存储的int32_t引用
static int32_t& ObjFile(void* obj) {
    // 将obj转换为char*类型，以便进行字节级别的指针运算
    // 然后加上12，获取偏移12个字节后的地址
    // 最后将其转换为int32_t*类型，并解引用以返回int32_t引用
    return *(reinterpret_cast<int32_t*>(reinterpret_cast<char*>(obj) + 12));
}



//计算对象大小的映射规则
class SizeClass
{
public:
    // 计算对齐
    // 整体控制在最多10%左右的内碎片浪费
    // [1, 64] 16byte对齐                   freelist[0, 4)
    // [64+1, 512] 64byte对齐               freelist[4, 11)
    // [512+1, 4*1024] 256byte对齐          freelist[11, 25)
    // [4*1024+1, 32*1024] 1*1024byte对齐   freelist[25, 56)
    // [32*1024+1, 256*1024] 4*1024byte对齐 freelist[56, 112)
    static inline size_t _RoundUp(size_t bytes, size_t alignNum) {
        /*
        // 普通写法
        size_t alignSize;
        if (bytes % alignNum != 0)
            alignSize = (bytes / alignNum + 1) * alignNum;
        else
            alignSize = bytes;

        return alignSize;
        */

        return (bytes + alignNum - 1) & ~(alignNum - 1);
    }

    // 计算对齐后的实际获取内存大小
    static inline size_t RoundUp(size_t size) {
        if (size <= 64) {
            return _RoundUp(size, 16);
        }
        else if (size <= 512) {
            return _RoundUp(size, 64);
        }
        else if (size <= 4 * 1024) {
            return _RoundUp(size, 256);
        }
        else if (size <= 32 * 1024) {
            return _RoundUp(size, 1024);
        }
        else if (size <= 256 * 1024) {
            return _RoundUp(size, 4096);
        }
        else {
            return _RoundUp(size, 1 << MY_PAGE_SHIFT);
        }
    }

    //alignNum是对齐数二进制位-1
    static inline size_t _Index(size_t bytes, size_t alignNum) {
        /*
        // 普通写法,alignNum是对齐数
        if (bytes % alignNum != 0)
            return bytes / alignNum;
        else
            return bytes / alignNum - 1;
        */

        return ((bytes + (1 << alignNum) - 1) >> alignNum) - 1;
    }

    // 计算映射到哪一个自由链表桶
    static inline size_t Index(size_t bytes) {
        assert(bytes <= 256 * 1024); // 断言 bytes 不超过 512 KB
        static int group_array[5] = { 4, 7, 14, 28, 56 }; // 每个区间的 freelist 数量

        // 根据不同的区间计算索引
        if (bytes <= 64) {
            // 16 字节对齐，4 位
            return _Index(bytes, 4);
        }
        else if (bytes <= 512) {
            // 64 字节对齐，6 位
            return _Index(bytes - 64, 6) + group_array[0];
        }
        else if (bytes <= 4 * 1024) {
            // 256 字节对齐，8 位
            return _Index(bytes - 512, 8) + group_array[1] + group_array[0];
        }
        else if (bytes <= 32 * 1024) {
            // 1 KB 对齐，10 位
            return _Index(bytes - 4 * 1024, 10) + group_array[2] + group_array[1] + group_array[0];
        }
        else if (bytes <= MAX_BYTES) {
            // 4 KB 对齐，12 位
            return _Index(bytes - 32 * 1024, 12) + group_array[3] + group_array[2] + group_array[1] + group_array[0];
        }
        else {
            // 不支持超过 512 KB 的内存块
            assert(false);
        }

        return 0; // 默认返回值，实际不会执行到这一步
    }

    // 一次从大内存切多少块小内存
    // (需要的内存大小)
    static size_t NumMoveSize(size_t size) {
        assert(size > 0);
        // [2, 256]，一次批量移动多少个对象的(慢启动)上限值
        // 小对象一次批量上限高
        // 大对象一次批量上限低
        size_t num = MAX_BYTES / size;
        if (num < 2)
            num = 2;

        if (num > 256)
            num = 256;

        return num;
    }

    // 计算一次向系统获取几个页
    static size_t NumMovePage(size_t size) {
        // 单个对象 8byte
        // ...
        // 单个对象 256KB
        size_t num = NumMoveSize(size);	// size大小的内存块数量
        size_t npage = num * size;	// 总共所需内存大小
        npage >>= MY_PAGE_SHIFT;	// 计算需要多少页内存
        if (npage == 0)
            npage = 1;

        return npage;
    }
};


// 管理多个连续页的大块内存跨度结构
struct Span
{
    //PAGE_ID _pageId = 0;		// 大块内存 "起始页" 的 "页号"
    void* _headPtr = nullptr;

    int32_t _n = -1;			// 页的数量
    int32_t _fileId = -1;       // 所属共享内存文件
    int32_t _spanPos = -1;      // 页所在共享内存文件中的头偏移量

    Span* _next = nullptr;		// 双向链表指针
    Span* _prev = nullptr;

    int32_t _objSize = 0;		// 切好的小对象大小
    int32_t _useCount = 0;		// 切好的小块内存, 分配计数
    void* _freeList = nullptr;	// 指向切好的小块内存的自由链表

    bool _isUse = false;		// 是否在被使用
};


// 带头双向循环链表
// Page Cache和Central Cache每个桶中的span链表
class SpanList
{
public:
    SpanList() {
        _head = new Span;
        _head->_next = _head;
        _head->_prev = _head;
    }

    Span* Begin() {
        return _head->_next;
    }

    Span* End() {
        return _head;
    }

    // 判断Span是否为空
    bool Empty() {
        return _head->_next == _head;
    }

    // 头插
    void PushFront(Span* span) {
        Inster(Begin(), span);
    }

    // 拆卸头部span,返回拆卸的Span
    Span* PopFront() {
        Span* front = _head->_next;
        Erase(front);

        return front;
    }

    // 在节点前插入新节点
    void Inster(Span* pos, Span* newSpan) {
        assert(pos);
        assert(newSpan);

        Span* prev = pos->_prev;
        prev->_next = newSpan;

        newSpan->_prev = prev;
        newSpan->_next = pos;

        pos->_prev = newSpan;
    }

    // 拆卸当前节点
    void Erase(Span* pos) {
        assert(pos);
        assert(pos != _head);

        Span* prev = pos->_prev;
        Span* next = pos->_next;

        prev->_next = next;
        next->_prev = prev;

        //无需delete
    }

    // // 获取桶锁
    // std::mutex& GetSpanMtx() {
    //     return _mtx;
    // }

private:
    Span* _head;	// 头结点
    //std::mutex _mtx; // 桶锁
};